package com.gqj.common.utils;

import com.gqj.common.utils.bean.BeanUtils;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.Supplier;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class StorageUtil {
    private static String date;
    private static long orderNum = 0l;
    private static final List<String> meterEquipCodeList = new ArrayList<>();
    private static final List<String> itEquipCodeList = new ArrayList<>();
    private static final List<String> concentratorEquipCodeList = new ArrayList<>();

    /**
     * 根据年月日生成十二位不重复编码
     *
     * @return
     */
    public static synchronized String getOrderNoTo12() {
        String str = new SimpleDateFormat("yyMMddHHmm").format(new Date());
        if (date == null || !date.equals(str)) {
            date = str;
            orderNum = 0l;
        }
        orderNum++;
        long orderNo = Long.parseLong((date)) * 100;
        orderNo += orderNum;
        return orderNo + "";
    }

    /**
     * 生成数据备份记录
     */
    public static boolean generateRecord(String filePath, String dbName, String dbUsername, String dbPassword, String dbIp) {
        boolean isFlag = false;
        String mysqlDumpPath = "C:\\";
        //时间
        String time = StorageUtil.getOrderNoTo12();
        String pathSql = filePath + time + "-elec-zjgw.sql";
        File fileSql = new File(pathSql);
        // 创建备份sql文件
        if (!fileSql.exists()) {
            try {
                fileSql.createNewFile();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // mysqldump -hlocalhost -uroot -p123456 db > /home/back.sql
        StringBuffer sb = new StringBuffer();
        sb.append("mysqldump");
        sb.append(" -h" + dbIp);
        sb.append(" -u" + dbUsername);
        sb.append(" -p" + dbPassword);
        sb.append(" " + dbName + " >");
        sb.append(pathSql);
        Runtime runtime = Runtime.getRuntime();
        try {
            Process process = runtime.exec("cmd /c" + mysqlDumpPath + sb.toString());
            isFlag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("数据备份" + isFlag);
        return isFlag;
    }

    /**
     * 单位缩进字符串。
     */
    private static String SPACE = "   ";

    /**
     * 返回格式化JSON字符串。
     *
     * @param json 未格式化的JSON字符串。
     * @return 格式化的JSON字符串。
     */
    public static String formatJson(String json) {
        StringBuffer result = new StringBuffer();

        int length = json.length();
        int number = 0;
        char key = 0;

        // 遍历输入字符串。
        for (int i = 0; i < length; i++) {
            // 1、获取当前字符。
            key = json.charAt(i);

            // 2、如果当前字符是前方括号、前花括号做如下处理：
            if ((key == '[') || (key == '{')) {
                // （1）如果前面还有字符，并且字符为“：”，打印：换行和缩进字符字符串。
                if ((i - 1 > 0) && (json.charAt(i - 1) == ':')) {
                    result.append('\n');
                    result.append(indent(number));
                }

                // （2）打印：当前字符。
                result.append(key);

                // （3）前方括号、前花括号，的后面必须换行。打印：换行。
                result.append('\n');

                // （4）每出现一次前方括号、前花括号；缩进次数增加一次。打印：新行缩进。
                number++;
                result.append(indent(number));

                // （5）进行下一次循环。
                continue;
            }

            // 3、如果当前字符是后方括号、后花括号做如下处理：
            if ((key == ']') || (key == '}')) {
                // （1）后方括号、后花括号，的前面必须换行。打印：换行。
                result.append('\n');

                // （2）每出现一次后方括号、后花括号；缩进次数减少一次。打印：缩进。
                number--;
                result.append(indent(number));

                // （3）打印：当前字符。
                result.append(key);

                // （4）如果当前字符后面还有字符，并且字符不为“，”，打印：换行。
                if (((i + 1) < length) && (json.charAt(i + 1) != ',')) {
                    result.append('\n');
                }

                // （5）继续下一次循环。
                continue;
            }

            // 4、如果当前字符是逗号。逗号后面换行，并缩进，不改变缩进次数。
            /*
             * if ((key == ',')) { result.append(key); result.append('\n');
             * result.append(indent(number)); continue; }
             */

            // 5、打印：当前字符。
            result.append(key);
        }

        return result.toString();
    }

    /**
     * 返回指定次数的缩进字符串。每一次缩进三个空格，即SPACE。
     *
     * @param number 缩进次数。
     * @return 指定缩进次数的字符串。
     */
    private static String indent(int number) {
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < number; i++) {
            result.append(SPACE);
        }
        return result.toString();
    }

    /**
     * 生成.json格式文件
     */
    public static boolean createJsonFile(String jsonString, String filePath, String fileName) {
        // 标记文件生成是否成功
        boolean flag = true;

        // 拼接文件完整路径
        String fullPath = filePath + File.separator + fileName + ".json";

        // 生成json格式文件
        try {
            // 保证创建一个新文件
            File file = new File(fullPath);
            if (!file.getParentFile().exists()) { // 如果父目录不存在，创建父目录
                file.getParentFile().mkdirs();
            }
            if (file.exists()) { // 如果已存在,删除旧文件
                file.delete();
            }
            file.createNewFile();

            if (jsonString.indexOf("'") != -1) {
                // 将单引号转义一下，因为JSON串中的字符串类型可以单引号引起来的
                jsonString = jsonString.replaceAll("'", "\\'");
            }
            if (jsonString.indexOf("\"") != -1) {
                // 将双引号转义一下，因为JSON串中的字符串类型可以单引号引起来的
                jsonString = jsonString.replaceAll("\"", "\\\"");
            }

            if (jsonString.indexOf("\r\n") != -1) {
                // 将回车换行转换一下，因为JSON串中字符串不能出现显式的回车换行
                jsonString = jsonString.replaceAll("\r\n", "\\u000d\\u000a");
            }
            if (jsonString.indexOf("\n") != -1) {
                // 将换行转换一下，因为JSON串中字符串不能出现显式的换行
                jsonString = jsonString.replaceAll("\n", "\\u000a");
            }

            // 格式化json字符串
            jsonString = formatJson(jsonString);

            // 将格式化后的字符串写入文件
            Writer write = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            write.write(jsonString);
            write.flush();
            write.close();
        } catch (Exception e) {
            flag = false;
            e.printStackTrace();
        }

        // 返回是否成功的标记
        return flag;
    }

    private static final int BUFFER_SIZE = 2 * 1024;


    /**
     * 压缩成ZIP 方法1
     *
     * @param srcDir           压缩文件夹路径
     * @param out              压缩文件输出流
     * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *                         <p>
     *                         false:所有文件跑到压缩包根目录下(注意：不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws RuntimeException 压缩失败会抛出运行时异常
     */

    public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure)

            throws RuntimeException {


        long start = System.currentTimeMillis();

        ZipOutputStream zos = null;

        try {

            zos = new ZipOutputStream(out);

            File sourceFile = new File(srcDir);

            compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);

            long end = System.currentTimeMillis();

            System.out.println("压缩完成，耗时：" + (end - start) + " ms");

        } catch (Exception e) {

            throw new RuntimeException("zip error from ZipUtils", e);

        } finally {

            if (zos != null) {

                try {

                    zos.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }


    }


    /**
     * 压缩成ZIP 方法2
     *
     * @param srcFiles 需要压缩的文件列表
     * @param out      压缩文件输出流
     * @throws RuntimeException 压缩失败会抛出运行时异常
     */

    public static void toZip(List<File> srcFiles, OutputStream out) throws RuntimeException {

        long start = System.currentTimeMillis();

        ZipOutputStream zos = null;

        try {

            zos = new ZipOutputStream(out);

            for (File srcFile : srcFiles) {

                byte[] buf = new byte[BUFFER_SIZE];

                zos.putNextEntry(new ZipEntry(srcFile.getName()));

                int len;

                FileInputStream in = new FileInputStream(srcFile);

                while ((len = in.read(buf)) != -1) {

                    zos.write(buf, 0, len);

                }

                zos.closeEntry();

                in.close();

            }

            long end = System.currentTimeMillis();

            System.out.println("压缩完成，耗时：" + (end - start) + " ms");

        } catch (Exception e) {

            throw new RuntimeException("zip error from ZipUtils", e);

        } finally {

            if (zos != null) {

                try {

                    zos.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }

    }


    /**
     * 递归压缩方法
     *
     * @param sourceFile       源文件
     * @param zos              zip输出流
     * @param name             压缩后的名称
     * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *                         <p>
     *                         false:所有文件跑到压缩包根目录下(注意：不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */

    private static void compress(File sourceFile, ZipOutputStream zos, String name,

                                 boolean KeepDirStructure) throws Exception {

        byte[] buf = new byte[BUFFER_SIZE];

        if (sourceFile.isFile()) {

            // 向zip输出流中添加一个zip实体，构造器中name为zip实体的文件的名字

            zos.putNextEntry(new ZipEntry(name));

            // copy文件到zip输出流中

            int len;

            FileInputStream in = new FileInputStream(sourceFile);

            while ((len = in.read(buf)) != -1) {

                zos.write(buf, 0, len);

            }

            // Complete the entry

            zos.closeEntry();

            in.close();

        } else {

            File[] listFiles = sourceFile.listFiles();

            if (listFiles == null || listFiles.length == 0) {

                // 需要保留原来的文件结构时,需要对空文件夹进行处理

                if (KeepDirStructure) {

                    // 空文件夹的处理

                    zos.putNextEntry(new ZipEntry(name + "/"));

                    // 没有文件，不需要文件的copy

                    zos.closeEntry();

                }


            } else {

                for (File file : listFiles) {

                    // 判断是否需要保留原来的文件结构

                    if (KeepDirStructure) {

                        // 注意：file.getName()前面需要带上父文件夹的名字加一斜杠,

                        // 不然最后压缩包中就不能保留原来的文件结构,即：所有文件都跑到压缩包根目录下了

                        compress(file, zos, file.getName(), KeepDirStructure);

                    } else {

                        compress(file, zos, file.getName(), KeepDirStructure);

                    }
                }
            }
        }
    }

    public static <S, T> List<T> copyList(List<S> sources, Supplier<T> target) {
        List<T> list = new ArrayList<>(sources.size());
        for (S source : sources) {
            T t = target.get();
            BeanUtils.copyProperties(source, t);
            list.add(t);
        }
        return list;
    }

    public static String ReadFile(InputStream inputStream) {
        BufferedReader reader = null;  //BufferedReader:入参有Reader对象和缓冲区大小（可不写）从缓冲区读取字符流，提高效率；缓冲区大小：默认8192，默认不需要传递建议都要用这个类去读取文件
        String laststr = "";
        try {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
            reader = new BufferedReader(inputStreamReader);
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {   //BufferedReader对象使用readLine()方法判断字符串是否为null判断是否为文件末尾
                laststr += tempString;
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return laststr;
    }

    static {
        meterEquipCodeList.add("3301000000270547");
        meterEquipCodeList.add("3301000000270753");
        meterEquipCodeList.add("3301000000270618");
        meterEquipCodeList.add("3301000000270713");
        meterEquipCodeList.add("3301000000270723");
        meterEquipCodeList.add("3301000000270431");
        meterEquipCodeList.add("3301000000270668");
        meterEquipCodeList.add("3301000000270674");
        meterEquipCodeList.add("3301000000270678");
        meterEquipCodeList.add("3301000000270474");
        meterEquipCodeList.add("3301000000270599");
        meterEquipCodeList.add("3301000000270643");

        itEquipCodeList.add("3302000000279138");
        itEquipCodeList.add("3302000000279141");
        itEquipCodeList.add("3302000000279164");
        itEquipCodeList.add("3302000000279166");
        itEquipCodeList.add("3302000000279142");
        itEquipCodeList.add("3302000000279151");
        itEquipCodeList.add("3302000000279147");

        concentratorEquipCodeList.add("3309000000279708");
        concentratorEquipCodeList.add("3309000000279696");
        concentratorEquipCodeList.add("3309000000279719");
        concentratorEquipCodeList.add("3309000000279787");
        concentratorEquipCodeList.add("0000000000000001");
        concentratorEquipCodeList.add("0000000000000002");
    }

    public static String getEquipCodeType(String equipCode) {
        if (meterEquipCodeList.contains(equipCode)) {
            return "01";
        } else if (itEquipCodeList.contains(equipCode)) {
            return "02";
        } else if (concentratorEquipCodeList.contains(equipCode)) {
            return "04";
        } else {
            return "";
        }
    }
}
